package server;

import classloader.WebAppClassLoader;
import mapper.EasyHost;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import servlet.HttpServlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author lbq
 * @version 1.0
 * @date 2021/1/21 21:07
 */
public class Bootstrap {

    private int port = 8080;

    private String appPath;

    private final Map<String, HttpServlet> servletMap = new HashMap<>();

    private final Map<String, EasyHost> hostMap = new HashMap<>();

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getAppPath() {
        return appPath;
    }

    public void setAppPath(String appPath) {
        this.appPath = appPath;
    }

    public void start() throws Exception {

        // 加载web.xml
        // loadServlet();

        // 加载server.xml
        loadServerXml();

        ServerSocket serverSocket = new ServerSocket(port);

        int corePoolSize = 10;
        int maximumPoolSize = 100;
        long keepAliveTime = 120L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue(200);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

        /*
            1.0 输出字符串
        */
        /*while (true) {
            Socket socket = serverSocket.accept();
            OutputStream out = socket.getOutputStream();
            String content = "hello world!";
            String response = HttpProtocolUtil.getHttpHeader200(content.length()) + content;
            out.write(response.getBytes());
            out.close();
            socket.close();
        }*/

        /*
            2.0 输出静态资源
        */
        /*while (true) {
            Socket socket = serverSocket.accept();
            Request request = new Request(socket.getInputStream());
            Response response = new Response(socket.getOutputStream());
            response.outputHtml(request.getUrl());
            socket.close();
        }*/

        /*
            3.0 输出servlet
        */
        /*while (true) {
            Socket socket = serverSocket.accept();
            Request request = new Request(socket.getInputStream());
            Response response = new Response(socket.getOutputStream());
            if (servletMap.get(request.getUrl()) == null) {
                response.outputHtml(request.getUrl());
            } else {
                HttpServlet httpServlet = servletMap.get(request.getUrl());
                httpServlet.service(request, response);
            }
            socket.close();
        }*/

        /*
            多线程改造
        */
        while (true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, hostMap);
            threadPoolExecutor.execute(requestProcessor);
        }
    }

    private void loadServerXml() throws Exception {
        InputStream resource = Bootstrap.class.getClassLoader().getResourceAsStream("server.xml");
        Document document = new SAXReader().read(resource);
        Element rootElement = document.getRootElement();
        Element element = (Element) rootElement.selectSingleNode("//service");
        Element connector = element.element("connector");
        String port = connector.attributeValue("port");
        // 设置监听端口
        this.port = Integer.parseInt(port);
        // webapps所在目录
        Element hostElement = element.element("engine").element("host");
        String path = hostElement.attributeValue("appBase");
        String host = hostElement.attributeValue("name");
        EasyHost easyHost = new EasyHost();
        easyHost.setHost(host);
        this.appPath = path;
        System.out.println("path = " + path);
        // 加载webapps下的所有部署的项目
        loadWebXml(path, easyHost);
    }

    private void loadWebXml(String path, EasyHost easyHost) throws Exception {
        File[] files = new File(path).listFiles();
        for (File file : files) {
            // 加载各个项目的web.xml、servlet
            loadSubjects(file, easyHost);
        }
        hostMap.put(easyHost.getHost(), easyHost);
    }

    private void loadSubjects(File file, EasyHost easyHost) throws Exception {
        String contextName = file.getName();
        EasyHost.EasyContext context = new EasyHost.EasyContext();
        context.setName(contextName);
        List<EasyHost.EasyWrapper> wrappers = context.getWrappers();
        File[] files = file.listFiles();

        WebAppClassLoader webAppClassLoader = new WebAppClassLoader();
        for (File child : files) {
            if (child.getAbsolutePath().endsWith(".xml")) {
                // 加载web.xml
                FileInputStream fileInputStream = new FileInputStream(child);
                Document document = new SAXReader().read(fileInputStream);
                Element rootElement = document.getRootElement();
                List<Element> servletList = rootElement.selectNodes("//servlet");
                for (Element element : servletList) {
                    EasyHost.EasyWrapper easyWrapper = new EasyHost.EasyWrapper();

                    String servletName = element.element("servlet-name").getText();
                    String servletClass = element.element("servlet-class").getText();

                    HttpServlet servlet = webAppClassLoader.loadClass(file, servletClass);

                    Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                    String url = servletMapping.element("url-pattern").getText();

                    easyWrapper.setServletClass(servletClass);
                    easyWrapper.setUrl(url);
                    easyWrapper.setServlet(servlet);
                    wrappers.add(easyWrapper);
                }
            }
        }
        List<EasyHost.EasyContext> contexts = easyHost.getContexts();
        contexts.add(context);
    }

    private void loadServlet() throws Exception {
        InputStream resource = Bootstrap.class.getClassLoader().getResourceAsStream("web.xml");
        System.out.println("加载web.xml文件!!!");
        Document document = new SAXReader().read(resource);
        Element rootElement = document.getRootElement();
        List<Element> servletList = rootElement.selectNodes("//servlet");
        for (Element element : servletList) {
            String servletName = element.element("servlet-name").getText();
            String servletClass = element.element("servlet-class").getText();

            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
            String url = servletMapping.element("url-pattern").getText();
            servletMap.put(url, (HttpServlet) Class.forName(servletClass).newInstance());
        }
    }

    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
